package com.tgh.gles2.c4.sphereworld;

import com.tgh.gles2.BaseRenderer;
import com.tgh.utils.GLFrame;
import com.tgh.utils.GLFrustum;
import com.tgh.utils.GLGeometryTransform;
import com.tgh.utils.GLMatrixStack;
import com.tgh.utils.GLShaderManager;
import com.tgh.utils.GLShaderManager.ShaderType;
import com.tgh.utils.GLTools;
import com.tgh.utils.GLTriangleBatch;
import com.tgh.utils.Math3D;
import com.tgh.utils.Matrix44f;
import com.tgh.utils.Vector3f;
import com.tgh.utils.Vector4f;

import android.content.Context;
import android.opengl.GLES20;
import android.os.SystemClock;

import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.Random;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class SphereWorldRenderer extends BaseRenderer {

    public SphereWorldRenderer(Context context) {
        super(context);
        torusBatch=new GLTriangleBatch();
        if (!torusBatch.loadDataFromSD("torus_04_015_30_30")) {
            torusBatch = GLTools.makeTorus(0.4f, 0.15f, 30, 30);
            torusBatch.cacheDataToSD("torus_04_015_30_30");
        }
        sphereBatch=new GLTriangleBatch();
        if (!sphereBatch.loadDataFromSD("sphere_01_26_13")) {
            sphereBatch = GLTools.makeSphere(0.1f, 26, 13);
            sphereBatch.cacheDataToSD("sphere_01_26_13");
        }
        initFloor();
        initSpheres();
        projectionMatrix = new GLMatrixStack();
        modelviewMatrix = new GLMatrixStack();
        transformPipleline = new GLGeometryTransform();
        cameraFrame = new GLFrame();
    }
    
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        shaderManager = new GLShaderManager();
        shaderManager.initStockShader();
        GLES20.glEnable(GLES20.GL_DEPTH_TEST);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
        viewFrustum = new GLFrustum(35f, (float)width/(float)height, 1, 100);
        projectionMatrix.loadMatrix(viewFrustum.getProjectionMatrix());
        transformPipleline.setMatrixStack(modelviewMatrix, projectionMatrix);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        float yRot=SystemClock.elapsedRealtime()/1000*20;
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT|GLES20.GL_DEPTH_BUFFER_BIT);
        modelviewMatrix.pushMatrix();
        Matrix44f cameraMatrix = cameraFrame.getCameraMatrix(false);
        modelviewMatrix.pushMatrix(cameraMatrix);
        drawFloor();
        Vector4f eyeLightPos=new Vector4f();
        Math3D.transformVector4(eyeLightPos, lightPos, cameraMatrix);
        for(int i=0;i<spheres.length;i++){
            modelviewMatrix.pushMatrix();
                modelviewMatrix.multMatrix(spheres[i]);
                shaderManager.useStockShader(ShaderType.POSITION_LIGHT, 
                        transformPipleline.getModelViewMatrix().getArray(),
                        transformPipleline.getProjectionMatrix().getArray(),
                        eyeLightPos.toArray(),
                        sphereColor);
                sphereBatch.draw();
            modelviewMatrix.popMatrix();
        }
        modelviewMatrix.translate(0, 0, -2.5f);
        modelviewMatrix.pushMatrix();
            modelviewMatrix.rotate(yRot, 0, 1, 0);
            shaderManager.useStockShader(ShaderType.POSITION_LIGHT, 
                    transformPipleline.getModelViewMatrix().getArray(),
                    transformPipleline.getProjectionMatrix().getArray(),
                    eyeLightPos.toArray(),
                    torusColor);
            torusBatch.draw();
        modelviewMatrix.popMatrix();
        
        modelviewMatrix.rotate(-2f*yRot, 0, 1, 0);
        modelviewMatrix.translate(0.8f, 0, 0);
        shaderManager.useStockShader(ShaderType.POSITION_LIGHT, 
                transformPipleline.getModelViewMatrix().getArray(),
                transformPipleline.getProjectionMatrix().getArray(),
                eyeLightPos.toArray(),
                sphereColor);
        sphereBatch.draw();
        modelviewMatrix.popMatrix();
        modelviewMatrix.popMatrix();
    }
    
    @Override
    public void onSurfaceDestroyed() {
    }
    
    public void up() {
        cameraFrame.moveForward(0.1f);
    }
    public void down() {
        cameraFrame.moveForward(-0.1f);
    }
    public void left() {
        cameraFrame.rotateWorld(angular, 0, 1, 0);
    }
    public void right() {
        cameraFrame.rotateWorld(-angular, 0, 1, 0);
    }
    
    private void initSpheres() {
        Random r=new Random();
        for(int i=0;i<spheres.length;i++){
            float x=r.nextInt(40)-20;
            float z=r.nextInt(40)-20;
            spheres[i]=new GLFrame();
            spheres[i].setOrigin(x, 0, z);
        }
    }
    
    private void initFloor(){
        ArrayList<Vector3f> vectors=new ArrayList<Vector3f>();
        for(float x=-20;x<=20.0f;x+=0.5f){
            vectors.add(new Vector3f(x, -0.55f, 20));
            vectors.add(new Vector3f(x, -0.55f, -20));
            
            vectors.add(new Vector3f(20, -0.55f, x));
            vectors.add(new Vector3f(-20, -0.55f, x));
        }
        float[] array=new float[vectors.size()*3];
        for(int i=0,size=vectors.size();i<size;i++){
            final Vector3f vector3f=vectors.get(i);
            array[i*3+0]=vector3f.x;
            array[i*3+1]=vector3f.y;
            array[i*3+2]=vector3f.z;
        }
        lineVertices = GLTools.makeFloatBuffer(array);
    }
    
    private void drawFloor() {
        shaderManager.useStockShader(ShaderType.FLAT, transformPipleline.getModelViewProjectionMatrix().getArray(),floorColor);
        GLES20.glVertexAttribPointer(GLShaderManager.GL_ATTRIBUTE_VERTEX, 3, GLES20.GL_FLOAT, false, 0, lineVertices);
        GLES20.glEnableVertexAttribArray(GLShaderManager.GL_ATTRIBUTE_VERTEX);
        GLES20.glDrawArrays(GLES20.GL_LINES, 0, lineVertices.capacity()/3);
    }
    
    protected GLFrame cameraFrame;
    protected static final float angular=(float) (30*Math.PI/180f);
    protected GLFrame[] spheres=new GLFrame[50];
    protected GLShaderManager shaderManager;
    protected GLTriangleBatch sphereBatch;
    protected GLTriangleBatch torusBatch;
    protected FloatBuffer lineVertices;
    protected GLFrustum viewFrustum;
    protected GLMatrixStack modelviewMatrix;
    protected GLMatrixStack projectionMatrix;
    protected GLGeometryTransform transformPipleline;
    private float[] floorColor={0,1,0,1};
    private float[] torusColor={1,0,0,1};
    private float[] sphereColor={0,0,1,1};
    private Vector4f lightPos=new Vector4f(0, 10, 5, 1);
}
